/**
 ******************************************************************************
 * @file   drv_f4_Mpwm_Stimer.h
 * @brief  主定时器-PWM 从定时器-定时器
 * @author Moon
 * @version V1.0.0
 * @date 2022/09/12
 ******************************************************************************
*/
/*从定时器通过主从模式将主定时器产生的PWM作为其输入进行计数，当从定时器达到所设定的数值后触发从定时器的中断*/

/* Includes ------------------------------------------------------------------*/
#include "drv_f4_Mpwm_Stimer.h"
/* Private defines -----------------------------------------------------------*/
typedef enum
{
	TIME_APB1 = 0,
	TIME_APB2,
} TIME_APBx_e;

typedef enum
{
	TIME_TIME2 = 0,
	TIME_TIME8,
	TIME_NUM,
} TIME_NUMx_e;

typedef struct
{
	char *drv;
	TIM_TypeDef *timx;
	TIME_APBx_e APBx;
	uint32_t arr_max;	//arr寄存器最大值
	uint32_t irq;
	uint32_t rcc_APBxPeriph;
	uint8_t afconfig;
	void (*TIMx_irq_CallBack)(void *);
	void *Caller;
} timer_param_t;

typedef struct
{
	char *master;		//主定时器
	char *slave;		//从定时器
	uint16_t TS_ITRx;	//Slave mode selection
} timer_SMS_table_t;

static timer_param_t timer_param[TIME_NUM] =
{
	[TIME_TIME2] = 
	{
		.drv = "TIM2",
		.timx = TIM2,
		.APBx = TIME_APB1,
		.arr_max = 0xFFFF,
		.rcc_APBxPeriph = RCC_APB1Periph_TIM2,
		.afconfig = GPIO_AF_TIM2,
		.irq = TIM2_IRQn,
	},
	[TIME_TIME8] = 
	{
		.drv = "TIM8",
		.timx = TIM8,
		.APBx = TIME_APB2,
		.arr_max = 0xFFFF,
		.rcc_APBxPeriph = RCC_APB2Periph_TIM8,
		.afconfig = GPIO_AF_TIM8,
		.irq = TIM8_UP_TIM13_IRQn,
	},
};

static timer_SMS_table_t SMS_table[] = 
{
	{
		.master = "TIM8",
		.slave = "TIM2",
		.TS_ITRx = TIM_TS_ITR1,   //TIMx 内部触发连接选择
	},
};
/* Private Struct  -----------------------------------------------------------*/

/* Private enum    -----------------------------------------------------------*/

/* Private Variable  ---------------------------------------------------------*/
//Pointer

//Array

//Const

/* Private function prototypes -----------------------------------------------*/
static int Timer_Check_name(const char *name);
static int Timer_Check_SMS(const char *Mname, const char *Sname);
static uint32_t calc_arr_load(drv_mpwm_stimer_t *this);

static int Mpwmx_Init(drv_mpwm_stimer_t *this, int index);
static int Stimerx_Init(drv_mpwm_stimer_t *this, int index);
static void TIMxCmd(drv_mpwm_stimer_t *this, uint8_t fg);
static void set_pwm_freq
(
	drv_mpwm_stimer_t *this,
	uint32_t freq,
	uint32_t timer_pluse
);
/***********************************************************************************
 * @brief 		
 * ex:
 * @par
 * None
 * @retval void None
 **********************************************************************************/
static int Timer_Check_name(const char *name)
{
	uint16_t i = 0;
    for (i = 0; i < TIME_NUM; i++)
	{
		if (strcmp(timer_param[i].drv,name) == 0)
			return i;
	}
    
    return -1;
}

/***********************************************************************************
 * @brief 		
 * ex:
 * @par
 * None
 * @retval void None
 **********************************************************************************/
static int Timer_Check_SMS(const char *Mname, const char *Sname)
{
	uint16_t i = 0;
	for (i = 0; i < TIME_NUM; i++)
	{
		if ((strcmp(SMS_table[i].master, Mname)) == 0 &&
			(strcmp(SMS_table[i].slave, Sname) == 0))
			return i;
	}

	return -1;
}

/***********************************************************************************
 * @brief 计算arr装载值
 * ex:
 * @par
 * None
 * @retval void None
 **********************************************************************************/
static uint32_t calc_arr_load(drv_mpwm_stimer_t *this)
{
	uint32_t load_data = 0;

	if (this == NULL)
		return 0;
	
	load_data = this->pwm_clock_freq / this->pwm_Prescaler / this->pwm_freq;
	if (load_data > timer_param[this->private.p_index].arr_max)
	{
		load_data = timer_param[this->private.p_index].arr_max;
	}
	else if (load_data < 0x02)
	{
		load_data = 0x02;
	}
	return load_data;
}

/***********************************************************************************
 * @brief 主PWM初始化
 * ex:
 * @par
 * None
 * @retval void None
 **********************************************************************************/
static int Mpwmx_Init(drv_mpwm_stimer_t *this, int index)
{
	uint32_t load_data = 0;
	TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
	TIM_OCInitTypeDef TIM_OCInitStructure;

	if (this == NULL)
		return -1;

		//TIMx时钟使能
	if (timer_param[index].APBx == TIME_APB2)
	{
		RCC_APB2PeriphClockCmd(timer_param[index].rcc_APBxPeriph, ENABLE);
	}
	else
	{
		RCC_APB1PeriphClockCmd(timer_param[index].rcc_APBxPeriph, ENABLE);
	}

	if (Common_Gpio_AFConfig(this->PIN_PWM,
							 timer_param[index].afconfig,
							 GPIO_PuPd_UP) < 0)
	{
		return -1;
	}

	load_data = calc_arr_load(this);
	TIM_TimeBaseStructure.TIM_Period = load_data - 1;								//自动重装载值
	TIM_TimeBaseStructure.TIM_Prescaler = this->pwm_Prescaler - 1;					//定时器分频
	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; 					//向上计数模式
	TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
	//TIM_TimeBaseStructure.TIM_RepetitionCounter = 0;
	TIM_TimeBaseInit(timer_param[index].timx, &TIM_TimeBaseStructure); //初始化定时器
	TIM_ARRPreloadConfig(timer_param[index].timx, ENABLE);

	//初始化TIMx Channex PWM模式
	TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
	TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //比较输出使能
	
	if (this->pwm_cmp >= 1)
		return -1;
	
	TIM_OCInitStructure.TIM_Pulse = (uint32_t)(load_data * this->pwm_cmp - 1); // 占空比
	TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low;
	
	switch (this->pwm_chx)
	{
		case TIMER_CH1:
			TIM_OC1Init(timer_param[index].timx, &TIM_OCInitStructure);
			TIM_OC1PreloadConfig(timer_param[index].timx, TIM_OCPreload_Enable);
			break;
		case TIMER_CH2:
			TIM_OC2Init(timer_param[index].timx, &TIM_OCInitStructure);
			TIM_OC2PreloadConfig(timer_param[index].timx, TIM_OCPreload_Enable);
			break;
		case TIMER_CH3:
			TIM_OC3Init(timer_param[index].timx, &TIM_OCInitStructure);
			TIM_OC3PreloadConfig(timer_param[index].timx, TIM_OCPreload_Enable);
			break;
		case TIMER_CH4:
			TIM_OC4Init(timer_param[index].timx, &TIM_OCInitStructure);
			TIM_OC4PreloadConfig(timer_param[index].timx, TIM_OCPreload_Enable);
			break;
		default:
			
		return -1;
	}

	TIM_Cmd(timer_param[index].timx, DISABLE);
	
	//TIM_Cmd(timer_param[index].timx, ENABLE);
	
	if (timer_param[index].timx == TIM8 || timer_param[index].timx == TIM1)  
		TIM_CtrlPWMOutputs(timer_param[index].timx, ENABLE);                       //高级定时器一定要加上，主输出使能
	
//	// Select the Master Slave Mode
	TIM_SelectMasterSlaveMode(timer_param[index].timx, TIM_MasterSlaveMode_Enable); //主模式
//	
//	// Master Mode selection
	TIM_SelectOutputTrigger(timer_param[index].timx, TIM_TRGOSource_Update);       //更新事件触发
	
	TIM_SetCompare3(timer_param[index].timx, (uint32_t)(load_data * this->pwm_cmp - 1));
	
	return 0;
}

/***********************************************************************************
 * @brief 从定时器初始化
 * ex:
 * @par
 * None
 * @retval void None
 **********************************************************************************/
static int Stimerx_Init(drv_mpwm_stimer_t *this, int index)
{
	int table_i = 0;

	if (this == NULL)
		return -1;

	//TIMx时钟使能
	if (timer_param[index].APBx == TIME_APB2)
	{
		RCC_APB2PeriphClockCmd(timer_param[index].rcc_APBxPeriph, ENABLE);
	}
	else
	{
		RCC_APB1PeriphClockCmd(timer_param[index].rcc_APBxPeriph, ENABLE);
	}

	TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
	TIM_TimeBaseStructure.TIM_Prescaler = 0;
	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
	TIM_TimeBaseStructure.TIM_Period = this->timer_pluse - 1;
	TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
	TIM_TimeBaseStructure.TIM_RepetitionCounter = 0;
	TIM_TimeBaseInit(timer_param[index].timx, &TIM_TimeBaseStructure);

	table_i = Timer_Check_SMS(this->PWM_DRV, this->TIMER_DRV);
	if (table_i < 0)
		return -1;
	
	// Slave Mode selection: 
	TIM_SelectSlaveMode(timer_param[index].timx, TIM_SlaveMode_Gated); //从模式
	TIM_SelectInputTrigger(timer_param[index].timx, SMS_table[table_i].TS_ITRx);		// TIM内部触发1

	TIM_ITRxExternalClockConfig(timer_param[index].timx, SMS_table[table_i].TS_ITRx); //设置TIM内部触发为外部时钟模式
	TIM_ClearITPendingBit(timer_param[index].timx, TIM_IT_Update);
	TIM_ITConfig(timer_param[index].timx, TIM_IT_Update, ENABLE);

    NVIC_InitTypeDef NVIC_InitStructure;
    NVIC_InitStructure.NVIC_IRQChannel                      = timer_param[index].irq;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority    = this->PreempPriority;      
    NVIC_InitStructure.NVIC_IRQChannelSubPriority           = 0;       
    NVIC_InitStructure.NVIC_IRQChannelCmd                   = ENABLE;
    NVIC_Init(&NVIC_InitStructure);

	timer_param[index].Caller = this;
	timer_param[index].TIMx_irq_CallBack = this->TIMx_irq_CallBack;	
	TIM_Cmd(timer_param[index].timx, DISABLE);
	
	return 0;
}

/***********************************************************************************
 * @brief 从定时器开关
 * ex:
 * @par fg-1:开 0:关
 * None
 * @retval void None
 **********************************************************************************/
static void TIMxCmd(drv_mpwm_stimer_t *this, uint8_t fg)
{
	if (this == NULL)
		return;
	
	this->private.pwmx->CNT = 0;
	//this->private.timx->CNT = 0;
	TIM_ClearITPendingBit(this->private.timx, TIM_IT_Update);
	if (fg == 0)
	{
		TIM_Cmd(this->private.pwmx, DISABLE);
		//TIM_Cmd(this->private.timx, DISABLE);		
	}
	else
	{
		TIM_Cmd(this->private.pwmx, ENABLE);
		//TIM_Cmd(this->private.timx, ENABLE);			
	}
}

/***********************************************************************************
 * @brief 设置主从定时器参数
 * ex:
 * @par freq：主PWM频率 timer_pluse:从定时器上限值
 * None
 * @retval void None
 **********************************************************************************/
static void set_pwm_freq
(
	drv_mpwm_stimer_t *this,
	uint32_t freq,
	uint32_t timer_pluse 
)
{
	uint32_t load_data;

	if (this == NULL)
		return;

	this->pwm_freq = freq;
	this->timer_pluse = timer_pluse;

	load_data = calc_arr_load(this);
	this->private.pwmx->ARR = load_data - 1;
	switch (this->pwm_chx)
	{
	case TIMER_CH1:
		this->private.pwmx->CCR1 = (uint32_t)(load_data * this->pwm_cmp - 1);
		break;
	case TIMER_CH2:
		this->private.pwmx->CCR2 = (uint32_t)(load_data * this->pwm_cmp - 1);
		break;
	case TIMER_CH3:
		this->private.pwmx->CCR3 = (uint32_t)(load_data * this->pwm_cmp - 1);
		break;
	case TIMER_CH4:
		this->private.pwmx->CCR4 = (uint32_t)(load_data * this->pwm_cmp - 1);
		break;
	default:
		break;
	}
	this->private.timx->CNT = 0;
	this->private.timx->ARR = timer_pluse;
	
	this->TIMxCmd(this,1); 
	
}

/***********************************************************************************
 * @brief 主从定时器初始化
 * ex:
 * @par
 * None
 * @retval void None
 **********************************************************************************/
int Drv_Mpwm_Stimer_Init(drv_mpwm_stimer_t *this)
{
	int pwm_index;
	int timer_index;

	if (this == NULL)
		return -1;

	pwm_index = Timer_Check_name(this->PWM_DRV);
	if (pwm_index < 0)
		return -1;

	this->private.p_index = (uint16_t)pwm_index;
	if (Mpwmx_Init(this, pwm_index) != 0)
		return -1;
	this->private.pwmx = timer_param[pwm_index].timx;
	
//	timer_index = Timer_Check_name(this->TIMER_DRV);
//	if (timer_index < 0)
//		return -1;
	
//	this->private.t_index = (uint16_t)timer_index;
//	if (Stimerx_Init(this, timer_index) != 0)
//		return -1;	
//	this->private.timx = timer_param[timer_index].timx;

	this->TIMxCmd = TIMxCmd;
	this->set_pwm_freq = set_pwm_freq;
	return 0;
}


void TIM2_IRQHandler(void)
{
	if (TIM_GetITStatus(TIM2, TIM_IT_Update) == SET)
	{
		timer_param_t *this = &timer_param[TIME_TIME2];
		TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
		if (this->TIMx_irq_CallBack != NULL)
			this->TIMx_irq_CallBack(this->Caller);
	}
}

/******************* (C) COPYRIGHT 2018 CIQTEK Samuel *****END OF FILE****/
